package com.demo.webflux.spring5core.framework.beans.support;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import com.demo.webflux.spring5core.framework.beans.config.BeanDefinition;

/**完成application.properties配置文件的解析工作，实现逻辑非常简单，通过构造方法获取从ApplicationContext传过来的locations配置文件路径，然后解析，扫描并保存所有相关的类并提供统一访问入口
 * @author zhangsulei
 *
 */
public class BeanDefinitionReader {

	private List<String> registerBeanClasses = new ArrayList<>();
	private Properties config = new Properties();
	// 固定配置文件中的key，相当于xml的规范
	private final String SCAN_PACKAGE = "scanPackage";

	public BeanDefinitionReader(String... locations) {
		// 通过url定位找到其所对应的文件，然后转换为文件流
		InputStream is = this.getClass().getClassLoader().getResourceAsStream(locations[0].replace("classpath:", ""));
		try {
			config.load(is);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(null != is) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		doScanner(config.getProperty(SCAN_PACKAGE));
	}

	private void doScanner(String scanPackage) {
		// 转换文件路径，实际上就是把.替换为/
		URL url = this.getClass().getClassLoader().getResource(scanPackage.replaceAll("\\.", "/"));
		//URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
		File classPath = new File(url.getFile());
		for(File file : classPath.listFiles()) {
			if(file.isDirectory()) {
				doScanner(scanPackage + "." + file.getName());
			} else {
				if(!file.getName().endsWith(".class")) {
					continue;
				}
				String className = (scanPackage + "." + file.getName().replace(".class", ""));
				registerBeanClasses.add(className);
			}
		}
	}

	public Properties getConfig() {
		return config;
	}

	/**把配置文件中扫描到的所有配置信息转换为BeanDefinition对象，以便于以后的ioc操作
	 * @return
	 */
	public List<BeanDefinition> loadBeanDefinitions(){
		List<BeanDefinition> result = new ArrayList<>();
		try {
			for (String className : registerBeanClasses) {
				Class<?> beanClass = Class.forName(className);
				if(beanClass.isInterface()) {
					continue;
				}
				result.add(doCreateBeanDefinition(toLowerFirstCase(beanClass.getSimpleName()), beanClass.getName()));

				Class<?>[] interfaces = beanClass.getInterfaces();
				for (Class<?> i : interfaces) {
					result.add(doCreateBeanDefinition(toLowerFirstCase(i.getSimpleName()), beanClass.getName()));
				}
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	private BeanDefinition doCreateBeanDefinition(String factoryBeanName, String beanClassName) {
		BeanDefinition beanDefinition = new BeanDefinition();
		beanDefinition.setBeanClassName(beanClassName);
		beanDefinition.setFactoryBeanName(factoryBeanName);
		return beanDefinition;
	}

	/**类名首字母改为小写
	 * 为了简化逻辑，就不做其他判断了
	 * @param simpleName
	 * @return
	 */
	private String toLowerFirstCase(String simpleName) {
		char[] chars = simpleName.toCharArray();
		// 因为大小写字母的ascii码相差32
		// 而且大写字母的ascii码要小于小写字母的ascii码
		// 在java中，对char做算术运算，实际上就是对ascii码做算术运算
		chars[0] += 32;
		return String.valueOf(chars);
	}

}
